/*
 *Copyright (c) [2019-2020]  C2comm, Inc.  All rights reserved.
 *
 *This program is free software; you can redistribute it and/or
 *modify it under the terms of the GNU General Public License
 *as published by the Free Software Foundation; either version 2
 *of the License, or (at your option) any later version.
 *
 *This program is distributed in the hope that it will be useful,
 *but WITHOUT ANY WARRANTY; without even the implied warranty of
 *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *GNU General Public License for more details.
 *
 *You should have received a copy of the GNU General Public License
 *along with this program; If not, see <https://www.gnu.org/licenses/>
 */
/*
 *Vendor: C2comm
 *Version: 1.0
 *Filename: PitDelay.v
 *Target Device: Altera
 *Author : 刘晓骏
*/

module PitDelay(
	input  wire         SYS2CORE_clk,
	input  wire         SYS2CORE_rst_n,
    
    input  wire [ 19:0] G_local_clk,
    input  wire [ 47:0] G_device_clk,
    
	input  wire [336:0] CONF2CORE_cm_static_conf,
    input  wire [ 42:0] G_current_state,//modify lxj 20200420
    
	input  wire         PP2PD_pcf_rx_cb_wr,
	input  wire [ 85:0] PP2PD_pcf_rx_cb,
	output wire         PD2PP_pcf_rx_cb_ready,
    
    input  wire         CC2PD_pcf_rx_cb_wr,
	input  wire [ 85:0] CC2PD_pcf_rx_cb,
	output wire         PD2CC_pcf_rx_cb_ready,

	output reg  [ 90:0] G_pcf_des,
	output reg          G_pcf_des_wr,
	input  wire         SCT2PD_pcf_des_ready
);
/*//////////////////////////////////////////////////////////
                    中间变量声明区域
*///////////////////////////////////////////////////////////
//本模块中所有中间变量(wire/reg/parameter)在此集中声明 
//PPBuffer_inst信号
wire        ppbuffer_wrreq;
wire [85:0] ppbuffer_wdata;
reg         ppbuffer_wrack;

//CCBuffer_inst信号
wire        ccbuffer_wrreq;
wire [85:0] ccbuffer_wdata;
reg         ccbuffer_wrack;

//DelayBuffer信号
reg  [ 7:0] dlybuffer_ivalid;
reg  [85:0] dlybuffer_idata;
wire [ 7:0] dlybuffer_iready;

wire [ 7:0] dlybuffer_owrreq;
wire [85:0] dlybuffer_odata [7:0];
reg  [ 7:0] dlybuffer_owrack;

reg  [ 7:0] cs_dly_done;//CS帧类型延时完成，高有效
reg  [ 7:0] ca_dly_done;//CA帧类型延时完成，高有效
reg  [ 7:0] in_dly_done;//IN帧类型延时完成，高有效

reg  [ 7:0] sel_dly_req;//根据优先级最终选定的延时完整信号，高有效(CS>CA>IN)

reg         iready_get;
wire [ 7:0] iready_grant_prior;

reg         seldone_get;
wire [ 7:0] seldone_grant_prior;

//倒置矩阵计算过程的中间变量
wire [85:0] precal_sel_data [7:0]; 
wire [ 7:0] invert_matrix [85:0];
wire [85:0] postcal_sel_odata;

wire [3:0] pcf_des_membersum;//待发出的membership的有效位数量

localparam  PCF_CS        = 2'd0,
            PCF_CA        = 2'd1,
            PCF_IN        = 2'd2;  
            
localparam  CM_INTEGRATE  = 6'b000001,
            CM_UNSYNC     = 6'b000010,
            CM_CA_ENABLED = 6'b000100,
            CM_WAIT_4_IN  = 6'b001000,
            CM_SYNC       = 6'b010000,
            CM_STABLE     = 6'b100000;
/*//////////////////////////////////////////////////////////
                    延迟缓存选择
*///////////////////////////////////////////////////////////
always @(posedge SYS2CORE_clk or negedge SYS2CORE_rst_n) begin
    if(SYS2CORE_rst_n == 1'b0) begin
        ppbuffer_wrack   <= 1'b0;
        ccbuffer_wrack   <= 1'b0;
        
        dlybuffer_ivalid <= {8{1'b0}};
        iready_get       <= 1'b0;
    end
    else begin
        if((ppbuffer_wrreq == 1'b1) && ((|iready_grant_prior) == 1'b1))begin
        //PP2PD_pcf_rx_cb有数据写入，且有空闲缓存buffer可用
            ppbuffer_wrack   <= 1'b1;
            ccbuffer_wrack   <= 1'b0;
            
            dlybuffer_ivalid <= iready_grant_prior;
            dlybuffer_idata  <= ppbuffer_wdata;
            iready_get       <= 1'b1;
        end
        else if((ccbuffer_wrreq == 1'b1) && ((|iready_grant_prior) == 1'b1))begin
        //CC2PD_pcf_rx_cb有数据写入，且有空闲缓存buffer可用
            ppbuffer_wrack   <= 1'b0;
            ccbuffer_wrack   <= 1'b1;
            
            dlybuffer_ivalid <= iready_grant_prior;
            dlybuffer_idata  <= ccbuffer_wdata;
            iready_get       <= 1'b1;
        end
        else begin
            ppbuffer_wrack   <= 1'b0;
            ccbuffer_wrack   <= 1'b0;
        
            dlybuffer_ivalid <= {8{1'b0}};
            iready_get       <= 1'b0;
        end
    end
end

/*//////////////////////////////////////////////////////////
                    延迟结果检测
*///////////////////////////////////////////////////////////
generate
    genvar i;
    for(i=0;i<8;i=i+1) begin:dly_result_mon
        always @* begin:dm
            if((dlybuffer_owrreq[i] == 1'b1) && 
               (dlybuffer_odata[i][85:38] <= G_device_clk)) begin
               //dlybuffer有数据且数据的延时已到达
                case(dlybuffer_odata[i][17:16])
                    PCF_CS: begin
                        cs_dly_done[i] = 1'b1;
                        ca_dly_done[i] = 1'b0;
                        in_dly_done[i] = 1'b0;
                    end
                    
                    PCF_CA: begin
                        cs_dly_done[i] = 1'b0;
                        ca_dly_done[i] = 1'b1;
                        in_dly_done[i] = 1'b0;
                    end
                    
                    PCF_IN: begin
                        cs_dly_done[i] = 1'b0;
                        ca_dly_done[i] = 1'b0;
                        in_dly_done[i] = 1'b1;
                    end
                    
                    default: begin
                        cs_dly_done[i] = 1'b0;
                        ca_dly_done[i] = 1'b0;
                        in_dly_done[i] = 1'b0;
                    end
                endcase
            end
            else begin
                cs_dly_done[i] = 1'b0;
                ca_dly_done[i] = 1'b0;
                in_dly_done[i] = 1'b0;
            end
        end
    end
endgenerate



/*//////////////////////////////////////////////////////////
                    延迟完成结果选择
*///////////////////////////////////////////////////////////

//根据规范中规定的PCF帧优先级对应的buffer(CS>CA>IN)
always @* begin
    if((|cs_dly_done) == 1'b1)
        sel_dly_req = cs_dly_done;
    else if((|ca_dly_done) == 1'b1)
        sel_dly_req = ca_dly_done;
    else
        sel_dly_req = in_dly_done;
end

/*通过倒置矩阵计算，根据优先级仲裁得到的seldone_grant_prior选择有效buffer的输出
    步骤1、通过seldone_grant_prior对全部buffer的输出信号进行预处理
       将seldone_grant_prior中bit为0的位对应的buffer输出全部清零，仅保留bit为1的位的输出
       例如seldone_grant_prior==8'b0000_0010,则仅保留dlybuffer_odata[1]的值，其余全部清零
       
    步骤2、将预处理的结果作为矩阵进行导致倒置，即行(row)/列(col)互换，方便后续进行计算
    
    步骤3、将倒置的矩阵的行(row)进行按位或操作，由于或操作的特性，即可得到有效输出
            如果全为0，则该bit为0
            只要有1bit为1(由于步骤1对其他信号进行了清零，也只会出现1bit为1)，则经过计算会保留该位的1
*/
//步骤1
generate
    genvar x;
    for(x=0;x<8;x=x+1) begin:pre_calulate
        assign precal_sel_data[x] = (seldone_grant_prior[x] == 1'b1) ? dlybuffer_odata[x] : {8{1'b0}};
    end
endgenerate

//步骤2
generate
    genvar row,col;
    for(row=0;row<8;row=row+1) begin:invert_magic_row
        for(col=0;col<86;col=col+1) begin:invert_magic_col
            assign invert_matrix[col][row] = precal_sel_data[row][col];
        end
    end
endgenerate

//步骤3
generate
    genvar y;
    for(y=0;y<86;y=y+1) begin:post_calulate
        assign postcal_sel_odata[y] = (|invert_matrix[y]);
    end
endgenerate

//计算待发出的membership的有效位数量
assign pcf_des_membersum = postcal_sel_odata[15] + 
                           postcal_sel_odata[14] + 
                           postcal_sel_odata[13] + 
                           postcal_sel_odata[12] + 
                           postcal_sel_odata[11] + 
                           postcal_sel_odata[10] + 
                           postcal_sel_odata[ 9] + 
                           postcal_sel_odata[ 8];



always @(posedge SYS2CORE_clk or negedge SYS2CORE_rst_n) begin
    if(SYS2CORE_rst_n == 1'b0) begin
        seldone_get  <= 1'b0;
        G_pcf_des    <= 91'b0;
        G_pcf_des_wr <= 1'b0;
        dlybuffer_owrack <= {8{1'b0}};
    end
    else begin
        if((SCT2PD_pcf_des_ready == 1'b1) && ((|seldone_grant_prior) == 1'b1)) begin
     
            seldone_get  <= 1'b1;
            dlybuffer_owrack <= seldone_grant_prior;
            
            G_pcf_des_wr <= 1'b1;
            
            if(((postcal_sel_odata[17:16] == PCF_CA) && (CONF2CORE_cm_static_conf[336] == 1'b1)) || 
               (postcal_sel_odata[17:16] == PCF_IN)) begin
                G_pcf_des[90:43] <= postcal_sel_odata[85:38]+CONF2CORE_cm_static_conf[294:275];
            end
            else begin
                G_pcf_des[90:43] <= postcal_sel_odata[85:38];
            end
            
       
            G_pcf_des[37:18] <= postcal_sel_odata[37:18];
            
      
            G_pcf_des[42:41] <=2'b0;
            if((G_current_state[42:37] == CM_INTEGRATE) || 
               (G_current_state[42:37] == CM_UNSYNC) ||
               (G_current_state[42:37] == CM_WAIT_4_IN))begin//mobidy by lxj 20200428当处于异步状态时，直接通过当前IN帧同步
                G_pcf_des[   40] <= (pcf_des_membersum >= CONF2CORE_cm_static_conf[ 99: 96]);
                G_pcf_des[   39] <= (pcf_des_membersum >= CONF2CORE_cm_static_conf[ 91: 88]);
                G_pcf_des[   38] <= (pcf_des_membersum >= CONF2CORE_cm_static_conf[111:108]);
            end
            else begin
                G_pcf_des[   40] <= 1'b0;
                G_pcf_des[   39] <= 1'b0;
                G_pcf_des[   38] <= 1'b0;
            end
            //Type+Membership+Intergration Cycle+ChannelID
            G_pcf_des[17: 0] <= postcal_sel_odata[17:0];
        end
        else begin
            seldone_get  <= 1'b0;
            G_pcf_des_wr <= 1'b0;
            dlybuffer_owrack <= {8{1'b0}};
        end
    end
end
/*//////////////////////////////////////////////////////////
                   IP调用区域
*///////////////////////////////////////////////////////////
//本模块调用的所有IP在该区域实例化
//例如fifo/ram/grant之类的IP.... 
InportBuffer #(
    .DWIDTH(86)
)PPBuffer_inst(
.clk(SYS2CORE_clk),//input
.rst_n(SYS2CORE_rst_n),//input
           
.idata_valid(PP2PD_pcf_rx_cb_wr),//input
.idata(PP2PD_pcf_rx_cb),//input
.idata_ready(PD2PP_pcf_rx_cb_ready),//output
    
.odata_wrreq(ppbuffer_wrreq),//output
.odata(ppbuffer_wdata),//output
.odata_wrack(ppbuffer_wrack)//input
);


InportBuffer #(
    .DWIDTH(86)
)CCBuffer_inst(
.clk(SYS2CORE_clk),//input
.rst_n(SYS2CORE_rst_n),//input
           
.idata_valid(CC2PD_pcf_rx_cb_wr),//input
.idata(CC2PD_pcf_rx_cb),//input
.idata_ready(PD2CC_pcf_rx_cb_ready),//output
    
.odata_wrreq(ccbuffer_wrreq),//output
.odata(ccbuffer_wdata),//output
.odata_wrack(ccbuffer_wrack)//input
);

generate
    genvar sum;
    for(sum=0;sum<8;sum=sum+1)begin:Dbuffer
        InportBuffer #(
            .DWIDTH(86)
        )DBuffer_inst(
        .clk(SYS2CORE_clk),//input
        .rst_n(SYS2CORE_rst_n),//input
                   
        .idata_valid(dlybuffer_ivalid[sum]),//input
        .idata(dlybuffer_idata),//input
        .idata_ready(dlybuffer_iready[sum]),//output
            
        .odata_wrreq(dlybuffer_owrreq[sum]),//output
        .odata(dlybuffer_odata[sum]),//output
        .odata_wrack(dlybuffer_owrack[sum])//input
        );
    end
endgenerate

prior_grant #(
    .GRANT_WIDTH(8),
    .PRIOR_LOW_OR_HIGH(0)
)iready_grant_inst(
    .clk(SYS2CORE_clk),
    .rst_n(SYS2CORE_rst_n),
    
    .req(dlybuffer_iready),
    
    .get(iready_get),
    
    .fix_prior(8'b11111111),
    
    .grant_prior(iready_grant_prior)
);

prior_grant #(
    .GRANT_WIDTH(8),
    .PRIOR_LOW_OR_HIGH(0)
)seldone_grant_inst(
    .clk(SYS2CORE_clk),
    .rst_n(SYS2CORE_rst_n),
    
    .req(sel_dly_req),
    
    .get(seldone_get),
    
    .fix_prior(8'b11111111),
    
    .grant_prior(seldone_grant_prior)
);
endmodule